From 363747b90f66f097fd45a6cd665adbaf7612188a Mon Sep 17 00:00:00 2001
From: Nikolai Kosjar <nikolai.kosjar@qt.io>
Date: Mon, 15 Jan 2018 12:51:18 +0100
Subject: [PATCH 2/3] Backport: [DeclPrinter] Allow printing fully qualified
 name of function declaration

https://reviews.llvm.org/D40013
---
 include/clang/AST/PrettyPrinter.h |  7 +++++-
 lib/AST/DeclPrinter.cpp           | 16 ++++++++----
 unittests/AST/DeclPrinterTest.cpp | 51 ++++++++++++++++++++++++++++++++++++---
 3 files changed, 64 insertions(+), 10 deletions(-)

diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h
index 274df220e1..edcef0ae24 100644
--- a/tools/clang/include/clang/AST/PrettyPrinter.h
+++ b/tools/clang/include/clang/AST/PrettyPrinter.h
@@ -50,7 +50,8 @@ struct PrintingPolicy {
       UseVoidForZeroParams(!LO.CPlusPlus),
       TerseOutput(false), PolishForDeclaration(false),
       Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar),
-      IncludeNewlines(true), MSVCFormatting(false) { }
+      IncludeNewlines(true), MSVCFormatting(false),
+      FullyQualifiedName(false) { }
 
   /// \brief Adjust this printing policy for cases where it's known that
   /// we're printing C++ code (for instance, if AST dumping reaches a
@@ -200,6 +201,10 @@ struct PrintingPolicy {
   /// prints anonymous namespaces as `anonymous namespace' and does not insert
   /// spaces after template arguments.
   bool MSVCFormatting : 1;
+
+  /// When true, print the fully qualified name of function declarations.
+  /// This is the opposite of SuppressScope and thus overrules it.
+  bool FullyQualifiedName : 1;
 };
 
 } // end namespace clang
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 37f08a4985..ea37abe8f6 100644
--- a/tools/clang/lib/AST/DeclPrinter.cpp
+++ b/tools/clang/lib/AST/DeclPrinter.cpp
@@ -510,13 +510,19 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
   PrintingPolicy SubPolicy(Policy);
   SubPolicy.SuppressSpecifiers = false;
   std::string Proto;
-  if (!Policy.SuppressScope) {
-    if (const NestedNameSpecifier *NS = D->getQualifier()) {
-      llvm::raw_string_ostream OS(Proto);
-      NS->print(OS, Policy);
+
+  if (Policy.FullyQualifiedName) {
+    Proto += D->getQualifiedNameAsString();
+  } else {
+    if (!Policy.SuppressScope) {
+      if (const NestedNameSpecifier *NS = D->getQualifier()) {
+        llvm::raw_string_ostream OS(Proto);
+        NS->print(OS, Policy);
+      }
     }
+    Proto += D->getNameInfo().getAsString();
   }
-  Proto += D->getNameInfo().getAsString();
+
   if (GuideDecl)
     Proto = GuideDecl->getDeducedTemplate()->getDeclName().getAsString();
   if (const TemplateArgumentList *TArgs = D->getTemplateSpecializationArgs()) {
diff --git a/unittests/AST/DeclPrinterTest.cpp b/unittests/AST/DeclPrinterTest.cpp
index dc1977d876..4cf8bce20e 100644
--- a/tools/clang/unittests/AST/DeclPrinterTest.cpp
+++ b/tools/clang/unittests/AST/DeclPrinterTest.cpp
@@ -104,15 +104,17 @@ PrintedDeclMatches(StringRef Code, const std::vector<std::string> &Args,
   return ::testing::AssertionSuccess();
 }
 
-::testing::AssertionResult PrintedDeclCXX98Matches(StringRef Code,
-                                                   StringRef DeclName,
-                                                   StringRef ExpectedPrinted) {
+::testing::AssertionResult
+PrintedDeclCXX98Matches(StringRef Code, StringRef DeclName,
+                        StringRef ExpectedPrinted,
+                        PrintingPolicyModifier PolicyModifier = nullptr) {
   std::vector<std::string> Args(1, "-std=c++98");
   return PrintedDeclMatches(Code,
                             Args,
                             namedDecl(hasName(DeclName)).bind("id"),
                             ExpectedPrinted,
-                            "input.cc");
+                            "input.cc",
+                            PolicyModifier);
 }
 
 ::testing::AssertionResult
@@ -350,6 +352,47 @@ TEST(DeclPrinter, TestFunctionDecl1) {
     "void A()"));
 }
 
+TEST(DeclPrinter, TestFreeFunctionDecl_FullyQualifiedName) {
+    ASSERT_TRUE(PrintedDeclCXX98Matches(
+      "void A();",
+      "A",
+      "void A()",
+      [](PrintingPolicy &Policy){ Policy.FullyQualifiedName = true; }));
+}
+
+TEST(DeclPrinter, TestFreeFunctionDeclInNamespace_FullyQualifiedName) {
+    ASSERT_TRUE(PrintedDeclCXX98Matches(
+      "namespace X { void A(); };",
+      "A",
+      "void X::A()",
+      [](PrintingPolicy &Policy){ Policy.FullyQualifiedName = true; }));
+}
+
+TEST(DeclPrinter, TestMemberFunction_FullyQualifiedName) {
+    ASSERT_TRUE(PrintedDeclCXX98Matches(
+      "struct X { void A(); };",
+      "A",
+      "void X::A()",
+      [](PrintingPolicy &Policy){ Policy.FullyQualifiedName = true; }));
+}
+
+TEST(DeclPrinter, TestMemberFunctionInNamespace_FullyQualifiedName) {
+    ASSERT_TRUE(PrintedDeclCXX98Matches(
+      "namespace Z { struct X { void A(); }; }",
+      "A",
+      "void Z::X::A()",
+      [](PrintingPolicy &Policy){ Policy.FullyQualifiedName = true; }));
+}
+
+TEST(DeclPrinter, TestMemberFunctionOutside_FullyQualifiedName) {
+    ASSERT_TRUE(PrintedDeclCXX98Matches(
+      "struct X { void A(); };"
+       "void X::A() {}",
+      functionDecl(hasName("A"), isDefinition()).bind("id"),
+      "void X::A()",
+      [](PrintingPolicy &Policy){ Policy.FullyQualifiedName = true; }));
+}
+
 TEST(DeclPrinter, TestFunctionDecl2) {
   ASSERT_TRUE(PrintedDeclCXX98Matches(
     "void A() {}",
-- 
2.15.1

